package com.melodyframe.common.context.loader;

import java.util.ArrayList;
import java.util.List;

import com.melodyframe.common.context.Context;
import com.melodyframe.common.tools.bean.BeanPropertyUtil;
import com.melodyframe.common.tools.bean.PropertyEntry;
import com.melodyframe.common.tools.convert.ConvertUtil;

public class ContextLoader {

	public static List<Object> load(Context context,
			List<ContextRequest<?>> requests) {
		List<Object> objects = new ArrayList<Object>();
		for (ContextRequest<?> request : requests) {
			objects.add(load(context, request));
		}
		return objects;
	}

	public static Object load(Context context, ContextRequest<?> request) {
		if (null != request.getName()) {
			return loadProperty(context, request);
		} else {
			return loadModel(context, request);
		}
	}

	public static Object loadProperty(Context context, ContextRequest<?> request) {
		Object sourceObject = getContextValue(context, request.getName(),
				request.getScope());
		if (null != sourceObject) {
			Class<?> sourceClass = sourceObject.getClass();
			if (sourceClass.isAssignableFrom(request.getClassType())) {
				return sourceObject;
			} else {
				if (ConvertUtil.support(request.getClassType())) {
					return ConvertUtil.convert(sourceObject,
							request.getClassType(), request.getFormat());
				}
			}
		}

		if (!request.getClassType().isPrimitive()) {
			return loadModel(context, request);
		} else {
			return null;
		}
	}

	protected static Object getContextValue(Context context, String name,
			String scope) {
		if (null != scope) {
			return context.get(name, scope);
		} else {
			return context.get(name);
		}
	}

	public static Object loadModel(Context context, ContextRequest<?> request) {
		Class<?> modelClass = request.getClassType();
		List<PropertyEntry<?>> properties = BeanPropertyUtil
				.getWriteableProperties(modelClass);
		try {
			Object model = modelClass.newInstance();
			for (PropertyEntry<?> property : properties) {
				ContextRequest<?> propertyRequest = request.property(property);
				Object value = loadProperty(context, propertyRequest);
				if (null != value
						|| !propertyRequest.getClassType().isPrimitive()) {
					property.getSetter().invoke(model, value);
				}
			}
			return model;
		} catch (Exception e) {// TODO
			e.printStackTrace();
			return null;
		}
	}
}
